Skip to content

Switch TLS certificates to APP mode and share via peer relation#461

Draft
Copilot wants to merge 6 commits intomainfrom
copilot/share-single-certificate-ha-deployment
Draft

Switch TLS certificates to APP mode and share via peer relation#461
Copilot wants to merge 6 commits intomainfrom
copilot/share-single-certificate-ha-deployment

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 13, 2026

In HA deployments, each unit was requesting its own TLS certificate (UNIT mode), hitting Let's Encrypt's rate limit of 5 certs per domain per 168h. Switch to APP mode so a single certificate is requested per application, with the leader sharing it to peers.

Core changes

  • src/state/tls.py: TLSInformation.from_charm() now returns Optional[TLSInformation] and handles both leader and non-leader paths — leader reads from TLS library, non-leader reads from peer relation via _from_peer_relation(). PEER_TLS_KEY constant is defined here as the canonical location for TLS state.

  • src/charm.py: Switch TLSCertificatesRequiresV4 from Mode.UNIT to Mode.APP. All callers use TLSInformation.from_charm() directly for leader/non-leader branching. Add _reconcile_certificates() which writes certs to disk and, if leader, shares to peer relation app databag. Observe haproxy-peers relation-changed to trigger reconcile on non-leader units when cert data arrives.

  • src/tls_relation.py: Add share_certificates_via_peer_relation() to serialize cert+chain+key into peer relation app databag. Remove the certificate_requests guard from certificate_available() since non-leader units receive certs from peers, not the TLS library.

Data flow

Leader unit:
  TLS library → get_assigned_certificates() → write to disk → share to peer relation app databag

Non-leader unit:
  peer relation-changed → TLSInformation.from_charm() reads peer relation app databag → write to disk

Test changes

  • Updated certificates_integration fixture to use local_app_data (APP mode stores CSRs in app databag, not unit databag)
  • Existing tests that exercise TLS-dependent paths now set leader=True
  • Added 7 new tests covering: leader shares certs to peer relation, non-leader reads from peer relation via from_charm(), non-leader with haproxy-route mode, round-trip serialization of TLSInformation, empty peer data returns None

Copilot AI and others added 3 commits April 13, 2026 10:31
- Changed TLSCertificatesRequiresV4 mode from Mode.UNIT to Mode.APP
- Added certificate sharing via haproxy-peer relation app databag
- Leader unit shares certificate data (cert, chain, private key) to peers
- Non-leader units read certificate data from peer relation
- Added _get_tls_information() helper for leader/non-leader branching
- Added _reconcile_certificates() to handle sharing after writing to disk
- Hooked peer relation-changed event to reconcile loop
- Updated test fixtures for APP mode (local_app_data for CSR data, leader=True)

Agent-Logs-Url: https://github.com/canonical/haproxy-operator/sessions/984ade73-92cb-4e20-89e1-2f2c22483668

Co-authored-by: Thanhphan1147 <42444001+Thanhphan1147@users.noreply.github.com>
- Test leader shares certificates to peer relation app databag
- Test non-leader reads certificates from peer relation
- Test non-leader without peer data skips TLS gracefully
- Test non-leader haproxy-route reads from peer relation
- Test share_certificates_via_peer_relation method directly
- Test get_tls_information_from_peer_relation with data
- Test get_tls_information_from_peer_relation without data returns None

Agent-Logs-Url: https://github.com/canonical/haproxy-operator/sessions/984ade73-92cb-4e20-89e1-2f2c22483668

Co-authored-by: Thanhphan1147 <42444001+Thanhphan1147@users.noreply.github.com>
- Fix ruff RUF059: prefix unused variable with underscore
- Fix ruff RUF015: use next() instead of list comprehension slice
- Fix mypy union-attr: add assertions for optional relation types
- Improve type annotation: use Application instead of typing.Any

Agent-Logs-Url: https://github.com/canonical/haproxy-operator/sessions/984ade73-92cb-4e20-89e1-2f2c22483668

Co-authored-by: Thanhphan1147 <42444001+Thanhphan1147@users.noreply.github.com>
Copilot AI changed the title [WIP] Enhance certificate sharing for HA deployment Switch TLS certificates to APP mode and share via peer relation Apr 13, 2026
Copilot AI requested a review from Thanhphan1147 April 13, 2026 10:41
Comment thread haproxy-operator/src/charm.py Outdated
Comment thread haproxy-operator/src/charm.py Outdated
self.haproxy_service.reconcile_default(charm_state)
self.unit.status = ops.ActiveStatus()

def _get_tls_information(
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot This logic needs to be moved to the from_charm method of the TLSInformation dataclass.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved the leader/non-leader branching logic into TLSInformation.from_charm() in state/tls.py. The method now returns Optional[TLSInformation] — leader path reads from the TLS library, non-leader path reads from the peer relation via _from_peer_relation(). Removed _get_tls_information() from charm.py and get_tls_information_from_peer_relation() from TLSRelationService. Also moved PEER_TLS_KEY constant to state/tls.py. See commit a3d6e5a.

Copilot AI and others added 2 commits April 14, 2026 11:34
…harm

- Moved _get_tls_information() logic from charm.py into TLSInformation.from_charm()
  in state/tls.py per reviewer feedback
- from_charm() now returns Optional[TLSInformation]: leader reads from TLS library,
  non-leader reads from peer relation via new _from_peer_relation() classmethod
- Removed _get_tls_information() method from charm.py
- Moved PEER_TLS_KEY constant to state/tls.py (canonical location for TLS state)
- Removed get_tls_information_from_peer_relation() from TLSRelationService
  (logic now in TLSInformation._from_peer_relation)
- Updated tests to test through TLSInformation.from_charm()

Agent-Logs-Url: https://github.com/canonical/haproxy-operator/sessions/96fecf67-9c28-47d1-8590-78ac4718d7c2

Co-authored-by: Thanhphan1147 <42444001+Thanhphan1147@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Share single certificate between units in HA deployment

2 participants